package in.rob.client.fragment.base;
import android.os.Bundle;
import android.os.Looper;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
import net.callumtaylor.swipetorefresh.helper.RefreshHelper;
import net.callumtaylor.swipetorefresh.helper.RefreshHelper.OnRefreshListener;
import net.callumtaylor.swipetorefresh.view.RefreshableListView;
import java.util.List;
import in.controller.adapter.base.RobinAdapter;
import in.controller.adapter.base.RobinAdapter.PageListener;
import in.controller.handler.base.StreamResponseListener;
import in.data.stream.base.Stream;
import in.lib.Constants;
import in.lib.loader.CacheLoader;
import in.lib.loader.Loader.OnFileLoadedListener;
import in.lib.utils.Debug;
import in.lib.utils.Views;
import in.lib.utils.Views.InjectView;
import in.lib.utils.Views.Injectable;
import in.lib.writer.CacheWriter;
import in.model.AdnModel;
import in.rob.client.R;
import in.rob.client.base.BaseActivity;
import lombok.Getter;
import lombok.Setter;
@Injectable
public abstract class StreamFragment extends BaseFragment implements PageListener, OnRefreshListener, OnItemClickListener, StreamResponseListener
{
private static final String INSTANCE_KEY_LOADING = "loading";
@Getter @InjectView private ListView listView;
@Getter @InjectView private View empty;
@Getter @InjectView private ProgressBar progress;
@Getter @Setter private RobinAdapter adapter;
@Getter @Setter private RefreshHelper refreshHelper;
@Getter private boolean loading = false;
@Getter private View loadMoreFooter;
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.stream_layout, container, false);
Views.inject(this, view);
listView.setEmptyView(empty);
return view;
}
@Override public void onCreate(Bundle savedInstanceState)
{
retrieveArguments(getArguments());
super.onCreate(savedInstanceState);
}
@Override public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
setupHeaders();
setupFooters();
setupAdapter();
if (adapter != null)
{
adapter.setPageListener(this);
adapter.setListView(listView);
listView.setAdapter(adapter);
}
listView.setOnItemClickListener(this);
refreshHelper = RefreshHelper.wrapRefreshable(this, this);
if (savedInstanceState != null)
{
retrieveArguments(savedInstanceState);
onDataReady();
}
else
{
initData();
}
if (isLoading())
{
refreshHelper.setRefreshing(true);
progress.setVisibility(View.VISIBLE);
}
attachResponses();
}
@Override public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (getAdapter() != null)
{
outState.putParcelable(Constants.EXTRA_ADAPTER_LIST, getAdapter().getStream());
}
outState.putBoolean(INSTANCE_KEY_LOADING, isLoading());
}
@Override public void onEndReached()
{
if (getAdapter().getStream().getMeta().isMoreAvailable() && !isLoading())
{
fetchStream(getAdapter().getStream().getMeta().getMinId(), true);
}
}
public void setLoading(boolean loading)
{
this.loading = loading;
}
public void initData()
{
progress.setVisibility(View.VISIBLE);
if (!TextUtils.isEmpty(getCacheKey()))
{
CacheLoader<Stream> loader = new CacheLoader<Stream>(getCacheKey());
loader.setOnFileLoadedListener(new OnFileLoadedListener<Stream>()
{
@Override public void onFileLoaded(Stream data, long age)
{
if (data != null)
{
progress.setVisibility(View.GONE);
getAdapter().setStream(data);
getAdapter().notifyDataSetChanged();
}
if (data == null
|| data.getItems().size() < 1
|| age > getCacheTimeout())
{
getRefreshHelper().refresh();
}
onDataReady();
}
});
loader.load(getCacheClass());
}
else
{
getRefreshHelper().refresh();
}
}
public void retrieveArguments(Bundle arguments)
{
if (arguments != null)
{
if (arguments.containsKey(Constants.EXTRA_ADAPTER_LIST))
{
getAdapter().setStream((Stream)arguments.getParcelable(Constants.EXTRA_ADAPTER_LIST));
getAdapter().notifyDataSetChanged();
arguments.remove(Constants.EXTRA_ADAPTER_LIST);
}
if (arguments.containsKey(INSTANCE_KEY_LOADING))
{
this.loading = arguments.getBoolean(INSTANCE_KEY_LOADING);
}
}
}
@Override public void onRefresh()
{
if (((BaseActivity)getActivity()) != null)
{
if (!(((BaseActivity)getActivity()).getPageAdapter().getCurrentFragment() == this))
{
getRefreshHelper().hideHelper();
}
}
setLoading(true);
fetchStream("", false);
}
@Override public void onDestroyView()
{
Views.reset(this);
adapter = null;
super.onDestroyView();
}
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
AdnModel model = getAdapter().getItem(position - getListView().getHeaderViewsCount());
onListItemClick(model);
}
public void onListItemClick(AdnModel item)
{
}
/**
* Called at the end of onActivityCreated (if savedInstanceState is not null) or after the cache
* was loaded At this point, the data should be loaded and it should do only final
* treatments and UI updates
*/
public void onDataReady()
{
}
/**
* Called to set up the stream page's list headers
*/
public void setupHeaders(){}
/**
* Called to set up the stream page's list footers
*/
public void setupFooters()
{
loadMoreFooter = LayoutInflater.from(getContext()).inflate(R.layout.loading_more_footer, getListView(), false);
getListView().addFooterView(loadMoreFooter, null, false);
}
/**
* Called to get the class for loading cache
* @return
*/
public abstract Class<Stream> getCacheClass();
/**
* Called to set up the stream page's adapter
*/
public abstract void setupAdapter();
/**
* Fetches the stream. Called when refreshed, or a new page is scrolled
* @param lastId The last ID to load
* @param append True if the stream is being appended, false if not
*/
public abstract void fetchStream(String lastId, boolean append);
/**
* Called when the stream has responded with a success or failure.
* @param stream The stream response or null if the stream failed
* @param append True if the stream is being appended, false if not
*/
@Override public void handleResponse(final Stream stream, boolean append)
{
if (Looper.myLooper() == Looper.getMainLooper())
{
Debug.out("Handling response " + this);
progress.setVisibility(View.GONE);
getRefreshHelper().finish();
if (stream != null)
{
if (getListView() instanceof RefreshableListView)
{
((RefreshableListView)getListView()).setBlockLayoutChildren(true);
}
if (append)
{
getAdapter().appendStream(stream);
}
else
{
final int[] lastViewPosition = getLastViewPosition(stream.getItems());
getAdapter().setStream(stream);
getListView().post(new Runnable()
{
@Override public void run()
{
getListView().setSelectionFromTop(lastViewPosition[0], lastViewPosition[1]);
}
});
}
getAdapter().notifyDataSetChanged();
getListView().post(new Runnable()
{
@Override public void run()
{
if (getListView() instanceof RefreshableListView)
{
((RefreshableListView)getListView()).setBlockLayoutChildren(false);
getListView().requestLayout();
}
}
});
writeToCache();
}
else
{
Toast.makeText(getContext(), R.string.stream_fail, Toast.LENGTH_SHORT).show();
}
}
else
{
throw new IllegalAccessError("Handle response was not called on the main thread");
}
}
public int[] getLastViewPosition(List<? extends AdnModel> items)
{
int pos = getListView().getLastVisiblePosition() - getListView().getHeaderViewsCount();
if (pos > -1 && getAdapter().getItem(pos) != null)
{
String currentPostId = getAdapter().getItem(pos).getId();
View v = getListView().getChildAt(Math.max(0, getListView().getChildCount() - 1));
int top = (v == null) ? 0 : v.getTop();
if (items != null)
{
for (int index = 0, count = items.size(); index < count; index++)
{
AdnModel item = items.get(index);
if (item.getId().equals(currentPostId))
{
pos = index;
break;
}
}
}
return new int[]{pos, top};
}
else
{
return new int[]{0, 0};
}
}
public void scrollToTop()
{
getListView().smoothScrollToPositionFromTop(0, 0, 200);
}
public void writeToCache()
{
if (!TextUtils.isEmpty(getCacheKey()))
{
CacheWriter writer = new CacheWriter(getCacheKey());
writer.write(getAdapter().getStream());
}
}
public String getCacheKey()
{
return null;
}
public int getCacheTimeout()
{
return 10 * 60 * 1000;
}
}